package com.zym.init.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zym.init.core.cache.ResourceCache;
import com.zym.init.core.exception.ServiceException;
import com.zym.init.core.plugin.storage.StorageDriver;
import com.zym.init.core.utils.AesUtils;
import com.zym.init.core.utils.SecurityUtils;
import com.zym.init.core.utils.SpringUtils;
import com.zym.init.enums.ResourceTypeEnum;
import com.zym.init.mapper.ResourceMapper;
import com.zym.init.mapper.StorageMapper;
import com.zym.init.model.dto.PageDTO;
import com.zym.init.model.po.ResourcePo;
import com.zym.init.model.po.StoragePo;
import com.zym.init.model.query.ResourceQuery;
import com.zym.init.model.vo.ResourceVo;
import com.zym.init.service.ResourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author zou
 * @description 针对表【resource(资源表)】的数据库操作Service实现
 * @createDate 2024-11-13 22:35:34
 */
@Slf4j
@Service
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, ResourcePo>
        implements ResourceService {

    private final ResourceMapper rMapper;
    private final StorageMapper sMapper;

    public ResourceServiceImpl(ResourceMapper rMapper, StorageMapper sMapper) {
        this.rMapper = rMapper;
        this.sMapper = sMapper;
    }

    /**
     * 获取列表
     */
    @Override
    public PageDTO<ResourceVo> getPage(ResourceQuery query) {
        // 获取默认配置
        QueryWrapper<StoragePo> qWrapper = new QueryWrapper<>();
        qWrapper.eq("is_default", true);
        List<StoragePo> storagePos = sMapper.selectList(qWrapper);
        if (storagePos.isEmpty()) {
            throw new ServiceException("请先设置默认存储配置");
        }
        StoragePo sPo = storagePos.get(0);
        // 获取上级ID
        Long pId = query.getParentResourceId();
        if (pId == null) {
            pId = 0L;
        }
        // 分页查询
        Page<ResourcePo> page = lambdaQuery()
                .eq(ResourcePo::getParentResourceId, pId)
                .eq(sPo.getStorageId() != null, ResourcePo::getStorageId, sPo.getStorageId())
                .eq(query.getResourceId() != null, ResourcePo::getResourceId, query.getResourceId())
                .like(query.getResourceName() != null, ResourcePo::getResourceName, query.getResourceName())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        // 封装返回
        return PageDTO.of(page, ResourcePo::toVo);
    }

    /**
     * 新增
     */
    @Override
    public boolean add(ResourceQuery query) {
        ResourceMapper rMapper = SpringUtils.getBean(ResourceMapper.class);
        ResourcePo resourcePo = new ResourcePo();
        resourcePo.setStorageId(query.getStorageId());
        resourcePo.setResourceType(query.getResourceType());
        resourcePo.setResourceName(query.getResourceName());
        resourcePo.setMediaType(query.getMediaType());
        resourcePo.setSize(query.getSize());
        resourcePo.setFileExtension(query.getFileExtension());
        resourcePo.setUploadUserId(query.getUploadUserId());
        resourcePo.setOriginalName(query.getOriginalName());
        resourcePo.setPath(query.getPath());
        resourcePo.setParentResourceId(query.getParentResourceId());
        int insert = rMapper.insert(resourcePo);
        query.setResourceId(resourcePo.getResourceId());
        // 缓存
        ResourceCache.set(query.getResourceId());
        return insert > 0;
    }

    /**
     * 检查目录是否存在
     *
     * @param path 目录路径
     */
    @Override
    public boolean checkDirectory(String path) {
        QueryWrapper<ResourcePo> wrapper = new QueryWrapper<>();
        wrapper.eq("resource_type", ResourceTypeEnum.DIRECTORY.getType());
        wrapper.eq("path", path);
        return count(wrapper) > 0;
    }

    /**
     * 删除
     *
     * @param ids id集合
     */
    @Override
    public boolean deleteBatchByIds(List<Long> ids) {
        List<String> paths = new ArrayList<>();
        List<ResourcePo> resourcePos = listByIds(ids);
        for (ResourcePo rPo : resourcePos) {
            if (rPo.getResourceId() != null && rPo.getResourceId() != 0) {
                // 获取子资源
                QueryWrapper<ResourcePo> qw = new QueryWrapper<>();
                qw.eq("parent_resource_id", rPo.getResourceId());
                List<ResourcePo> children = rMapper.selectList(qw);
                if (!children.isEmpty()) {
                    // 递归删除子资源
                    deleteBatchByIds(children.stream().map(ResourcePo::getResourceId).toList());
                }
            }
            // 获取文件存储路径
            if (Objects.equals(rPo.getResourceType(), ResourceTypeEnum.FILE.getType())) {
                paths.add(rPo.getPath());
            }
        }
        // 物理删除文件
        StorageDriver storageDriver = new StorageDriver();
        paths.forEach(System.out::println);
        storageDriver.delete(paths);
        // 删除数据库中的记录
        int count = rMapper.deleteBatchIds(ids);
        if (count > 0) {
            // 删除缓存
            ResourceCache.del(ids);
        }
        return count > 0;
    }

    /**
     * 获取面包屑列表
     *
     * @param id 资源id
     */
    @Override
    public List<ResourceVo> getBreadcrumb(Long id) {
        if (id == null || id == 0) {
            return new ArrayList<>();
        }
        List<ResourceVo> breadcrumb = new ArrayList<>();
        ResourcePo rPo = getById(id);
        if (rPo != null) {
            ResourceVo resourceVo = new ResourceVo();
            resourceVo.setResourceId(rPo.getResourceId());
            resourceVo.setResourceName(rPo.getResourceName());
            breadcrumb.add(resourceVo);
            Long parentResourceId = rPo.getParentResourceId();
            if (parentResourceId != null) {
                breadcrumb.addAll(getBreadcrumb(parentResourceId));
            }
        }
        return breadcrumb;
    }

    /**
     * 编辑
     */
    @Override
    public boolean edit(ResourceQuery query) {
        // 检查文件名是否重复
        if (query.getResourceName() != null) {
            checkResourceName(query.getResourceId(), query.getResourceName());
        }
        // 检查文件名是否过长
        if (query.getResourceName() != null && query.getResourceName().length() > 64) {
            throw new ServiceException("文件名过长，最长64个字符");
        }
        // 判断父ID是否合法
        if (query.getParentResourceId() != null && query.getParentResourceId() != 0) {
            if (query.getParentResourceId().equals(query.getResourceId())) {
                throw new ServiceException("不能将资源放入自身目录");
            }
            ResourcePo parent = getById(query.getParentResourceId());
            if (parent == null) {
                throw new ServiceException("父级资源不存在");
            }
            if (Objects.equals(parent.getResourceType(), ResourceTypeEnum.FILE.getType())) {
                throw new ServiceException("父级资源不能为文件");
            }
        }
        ResourcePo po = new ResourcePo();
        // 文件ID
        po.setResourceId(query.getResourceId());
        // 文件名
        po.setResourceName(query.getResourceName());
        // 文件后缀
        po.setFileExtension(query.getFileExtension());
        // 父级ID
        po.setParentResourceId(query.getParentResourceId());
        boolean result = updateById(po);
        if (result) {
            // 更新缓存
            ResourceCache.set(query.getResourceId());
        }
        return result;
    }

    /**
     * 获取资源对象
     *
     * @param id 资源id
     */
    @Override
    public ResourcePo getById(Long id) {
        if (id == null || id == 0) {
            return null;
        }
        ResourcePo rPo = ResourceCache.get(id);
        if (rPo == null) {
            // 缓存未命中,从数据库查询
            rPo = rMapper.selectById(id);
            System.out.println("从数据库查询" + rPo);
            if (rPo == null) {
                throw new ServiceException("资源不存在");
            }
            // 将资源信息放入缓存
            ResourceCache.set(id);
        }
        return rPo;
    }

    /**
     * 获取加密id
     *
     * @param id 资源id
     * @return 加密id
     */
    @Override
    public String getEncryptionId(Long id) {
        // 加密密文
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", id);
        return AesUtils.encrypt(jsonObject.toJSONString());
    }

    /**
     * 创建目录
     *
     * @param rootId 根目录ID
     * @param path 目录路径 如：a/b/c/d
     * @return 目录id
     */
    @Override
    public Long createDirectory(Long rootId, String path) {
        if (!StringUtils.hasLength(path)) {
            return 0L;
        }
        // 如果首尾有斜杠，去除首尾斜杠
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        if (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
        // 拆分文件夹
        String[] paths = path.split("/");
        // 获取默认配置
        StorageDriver storageDriver = new StorageDriver();
        // 上级的ID
        Long pId = rootId == null ? 0L : rootId;
        // 创建文件夹
        for (int i = 0; i < paths.length; i++) {
            String s = paths[i];
            // 检查文件夹是否存在
            QueryWrapper<ResourcePo> qw = new QueryWrapper<>();
            qw.eq("resource_type", ResourceTypeEnum.DIRECTORY.getType());
            qw.eq("resource_name", s);
            qw.eq("parent_resource_id", 0);
            // 同一存储配置下
            qw.eq("storage_id", storageDriver.getStorageId());
            // 同一父级目录下
            qw.eq("parent_resource_id", pId);
            List<ResourcePo> list = list(qw);
            if (list.isEmpty()) {
                // 创建文件夹
                ResourceQuery rQuery = new ResourceQuery();
                rQuery.setStorageId(storageDriver.getStorageId());
                rQuery.setResourceType(ResourceTypeEnum.DIRECTORY.getType());
                rQuery.setResourceName(s);
                rQuery.setUploadUserId(SecurityUtils.getUserId());
                rQuery.setParentResourceId(pId);
                StringBuilder parentPath = new StringBuilder();
                for (int j = 0; j < (i + 1); j++) {
                    // 如果是第一个，不拼接斜杠
                    if (j != 0) {
                        parentPath.append("/");
                    }
                    parentPath.append(paths[j]);
                }
                rQuery.setPath(parentPath.toString());
                boolean save = add(rQuery);
                if (save) {
                    // 更新缓存
                    ResourceCache.set(rQuery.getResourceId());
                    pId = rQuery.getResourceId();
                }
            } else {
                pId = list.get(0).getResourceId();
            }
        }
        return pId;
    }

    /**
     * 检查文件名是否重复
     */
    private void checkResourceName(Long resourceId, String resourceName) {
        ResourcePo rPo = getById(resourceId);
        QueryWrapper<ResourcePo> wrapper = new QueryWrapper<>();
        wrapper.ne("resource_id", resourceId);
        wrapper.eq("storage_id", rPo.getStorageId());
        wrapper.eq("parent_resource_id", rPo.getParentResourceId());
        wrapper.eq("resource_name", resourceName);
        if (count(wrapper) > 0) {
            throw new ServiceException("文件名重复");
        }
    }
}




